﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using System.Reflection;

#if !DOT_NET_BUILD_FROM_SOURCE
using Microsoft.DotNet.Cli.Installer.Windows.Security;
#endif

using Microsoft.Win32;

namespace Microsoft.DotNet.Cli.Commands.Workload;

internal static class SignCheck
{
    internal static readonly string OnlineRevocationCheckPolicyKeyName = "AllowOnlineRevocationChecks";
    internal static readonly string VerifySignaturesPolicyKeyName = "VerifySignatures";

    private static readonly string s_WorkloadPolicyKey = @"SOFTWARE\Policies\Microsoft\dotnet\Workloads";

    private static readonly string s_dotnet = Assembly.GetExecutingAssembly().Location;

    /// <summary>
    /// Determines whether dotnet.dll is signed.
    /// </summary>
    /// <returns><see langword="true"/> if dotnet is signed; otherwise, <see langword="false"/>.</returns>
    public static bool IsDotNetSigned()
    {
        if (OperatingSystem.IsWindows())
        {
#if !DOT_NET_BUILD_FROM_SOURCE
            // API is only available on XP and Server 2003 or later versions. .NET requires Win7 minimum.
#pragma warning disable CA1416
            // We don't care about trust in this case, only whether or not the file has a signature as that determines
            // whether we'll trigger sign verification for workload operations.
            return Signature.IsAuthenticodeSigned(s_dotnet, AllowOnlineRevocationChecks()) == 0;
#pragma warning restore CA1416
#endif
        }

        return false;
    }

    /// <summary>
    /// Determines whether revocation checks can go online based on the global policy setting in the registry.
    /// </summary>
    /// <returns><see langword="true"/> if the policy key is absent or set to a non-zero value; <see langword="false"/> if the policy key is set to 0.</returns>
    public static bool AllowOnlineRevocationChecks()
    {
        if (OperatingSystem.IsWindows())
        {
            using RegistryKey policyKey = Registry.LocalMachine.OpenSubKey(s_WorkloadPolicyKey);

            return ((int?)policyKey?.GetValue(OnlineRevocationCheckPolicyKeyName) ?? 1) != 0;
        }

        return true;
    }

    /// <summary>
    /// Determines whether the global policy to enforce signature checks for workloads is set.
    /// </summary>
    /// <returns><see langword="true"/> if the policy is set; <see langword="false"/> otherwise.</returns>
    public static bool IsWorkloadSignVerificationPolicySet()
    {
        if (OperatingSystem.IsWindows())
        {
            using RegistryKey policyKey = Registry.LocalMachine.OpenSubKey(s_WorkloadPolicyKey);

            return ((int?)policyKey?.GetValue(VerifySignaturesPolicyKeyName) ?? 0) != 0;
        }

        return false;
    }
}
